﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Management;
using System.Collections;
// namespaces necesarios para conexión a bd
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;

namespace Persistencia_y_capa_de_negocio
{
    public class CADRecurso
    {
        private static readonly CADRecurso instancia = new CADRecurso();
        public static CADRecurso Instancia
        {
            get { return instancia; }
        }

        // Cadena de conexión.
        private string cadCon;
        private SqlDataAdapter da;
        private SqlDataAdapter dae;
        private SqlDataAdapter daec;
        private SqlDataAdapter dauc;
        private SqlConnection c;
        private DataSet vdb;

        /// <summary>
        /// Constructor.
        /// </summary>
        public CADRecurso()
        {
            try
            {
                // Establecemos la cadena de conexión desde app.config.
                cadCon = ConfigurationManager.ConnectionStrings["conexion"].ConnectionString;
                
                // Creamos la base de datos virtual.
                vdb = new DataSet();

                // Obtenemos una conexión.
                c = new SqlConnection(cadCon);

                // Almacenamos la base de datos en local.
                da = new SqlDataAdapter("Select * from recursos", c);
                da.Fill(vdb, "Recursos");

                // DataAdapter para la tabla recursos generados por un edificio.
                dae = new SqlDataAdapter("Select * from generarecurso", c);
                dae.Fill(vdb, "GeneraRecurso");

                // DataAdapter para la tabla de costes de edificios.
                daec = new SqlDataAdapter("select * from costedificio", c);
                daec.Fill(vdb, "CostesEdificio");

                // DataAdapter para la tabla de costes de unidades.
                dauc = new SqlDataAdapter("select * from costeunidad", c);
                dauc.Fill(vdb, "CostesUnidad");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }



        }

        /// <summary>
        /// Insertamos en la base de datos el recurso, sin embargo si ya existe, se modificará su contenido.
        /// </summary>
        /// <param name="re">Variable con los datos necesarios que contiene un recurso.</param>
        public bool InsertarRecurso(ENRecurso re)
        {
            // Indica si se ha realizado la inserción.
            bool insertado = false;

            // Obtenemos la tabla recursos.
            DataTable t = new DataTable();
            t = vdb.Tables["Recursos"];
            
            try
            {
                // Comprobamos si ya existe un recurso con ese nombre.
                DataRow r = t.Select("nombre = \'" + re.Nombre + "\'")[0];

                // Actualizamos la información del edificio.
                r["nombre"] = re.Nombre;
                r["cantidad_base"] = re.Ratio.ToString();
                r["descripcion"] = re.Descripcion;
                r["admin"] = re.Admin;
                SqlCommandBuilder command = new SqlCommandBuilder(da);

                // Actualizamos los cambios en la BD real.
                da.Update(vdb, "Recursos");
            }
            catch (Exception)
            {
                // Significa que el resultado ha sido null. O sea que hay que insertar, no modificar.
                DataRow r = t.NewRow();

                // Insertamos los valores del nuevo recurso.
                r["nombre"] = re.Nombre;
                r["cantidad_base"] = re.Ratio.ToString();
                r["descripcion"] = re.Descripcion;
                r["admin"] = re.Admin;

                // Añadimos la nueva fila a la tabla virtual.
                t.Rows.Add(r);
                SqlCommandBuilder command = new SqlCommandBuilder(da);

                // Actualizamos los cambios en la BD real.
                da.Update(vdb, "Recursos");

                // Se ha realizado la inserción.
                insertado = true;
            }

            // Devolvemos el resultado.
            return insertado;
        }

        /// <summary>
        /// Devuelve un ArrayList con todos los recursos de la base de datos.
        /// </summary>
        /// <returns>Devuelve un ArrayList con todos los recursos de la base de datos.</returns>
        public ArrayList getRecursos()
        {
            // ArrayList de recursos.
            ArrayList lista = new ArrayList();

            // Obtenemos la tabla recursos.
            DataTable t = new DataTable();
            t = vdb.Tables["Recursos"];

            t.Clear();

            da = new SqlDataAdapter("select * from recursos", c);

            da.Fill(vdb, "Recursos");    // Ahora tenemos todo el contenido de edificios en local.

            t = vdb.Tables["Recursos"];

            // Extraemos los ENRecurso de cada fila de la base de datos.
            foreach (DataRow r in t.Rows)
            {
                ENRecurso re = new ENRecurso();

                // Insertamos los datos en el nuevo recurso.
                re.Id = Convert.ToInt32(r["id"]);
                re.Nombre = r["nombre"].ToString().Trim();
                re.Ratio = Convert.ToInt32(r["cantidad_base"]);
                re.Descripcion = r["descripcion"].ToString().Trim();
                re.Admin = r["admin"].ToString().Trim();
                lista.Add(re);
            }

            // Devolvemos el resultado.
            return lista;
        }

        /// <summary>
        /// Devuelve la entidad de negocio recurso nombre con la información de la base de datos.
        /// </summary>
        /// <param name="nombre">Nombre del recurso.</param>
        /// <returns>Entidad de negocio con ese nombre.</returns>
        public ENRecurso getRecurso(string nombre)
        {
            // Obtenemos la tabla recursos.
            DataTable t = new DataTable();
            t = vdb.Tables["Recursos"]; 
            
            try
            {
                // Comprobamos si existe un recurso con ese nombre.
                DataRow r = t.Select("nombre = \'" + nombre + "\'")[0];

                // Creamos el recurso
                ENRecurso re = new ENRecurso();
                re.Id = Convert.ToInt32(r["id"]);
                re.Nombre = r["nombre"].ToString().Trim();
                re.Ratio = Convert.ToInt32(r["cantidad_base"]);
                re.Descripcion = r["descripcion"].ToString().Trim();
                re.Admin = r["admin"].ToString().Trim();

                // Devolvemos el resultado.
                return re;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// Devuelve el número de recursos que han sido creados por el administrador que recibe por parámetro.
        /// </summary>
        /// <param name="nombre">Nombre del administrador.</param>
        /// <returns>Devuelve un entero con la cantidad de recursos que han sido creados por el administrador.</returns>
        public int getNumRecursosPorAdmin(string nombre)
        {
            // Obtenemos la tabla recursos.
            DataTable t = new DataTable();
            t = vdb.Tables["Recursos"];

            try
            {
                // Devolvemos la cantidad de recursos con ese creador.
                return t.Select("admin = \'" + nombre + "\'").Count();
                
            }
            catch (Exception)
            {
                return 0;
            }
        }

        /// <summary>
        /// Borra el recurso seleccionado de la base de datos.
        /// </summary>
        /// <param name="nombre">Nombre del recurso que queremos borrar.</param>
        public void EliminaRecurso(string nombre)
        {
            // Obtenemosla tabla recursos, costes de edificios, de unidades y generaciones de recursos
            DataTable t = vdb.Tables["Recursos"];
            DataTable tce = vdb.Tables["CostesEdificio"];
            DataTable tcu = vdb.Tables["CostesUnidad"];
            DataTable tgr = vdb.Tables["GeneraRecurso"];


            try
            {
                // Comprobamos si existe algún recurso con ese nombre.
                DataRow r = t.Select("nombre = \'" + nombre + "\'")[0];

                int idRecurso = Convert.ToInt32(r["id"]);

                // Primero eliminamos todas las referencias del recurso.

                // costes de edificio.
                foreach (DataRow rCoste in tce.Select("nomrecurso = \'" + idRecurso + "\'"))
                {
                    rCoste.Delete();
                }

                SqlCommandBuilder cm = new SqlCommandBuilder(daec);
                daec.Update(vdb, "CostesEdificio");

                // costes de unidad

                foreach (DataRow rCosteUnidad in tcu.Select("recurso = \'" + idRecurso + "\'"))
                {
                    rCosteUnidad.Delete();
                }

                cm = new SqlCommandBuilder(dauc);
                dauc.Update(vdb, "CostesUnidad");


                // Generar recursos
                foreach (DataRow rGeneraRecurso in tgr.Select("nomrecurso = \'" + idRecurso + "\'"))
                {
                    rGeneraRecurso.Delete();
                }

                cm = new SqlCommandBuilder(dae);
                dae.Update(vdb, "GeneraRecurso");

                // Eliminamos el recurso.
                r.Delete();
                SqlCommandBuilder command = new SqlCommandBuilder(da);

                // Actualizamos los cambios en la BD real.
                da.Update(vdb, "Recursos");
            }
            catch(Exception ex)
            {
                // Mostramos un error.
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Devuelve la cantidad de recursos totales que existen.
        /// </summary>
        /// <returns>Devuelve la cantidad de recursos totales que existen.</returns>
        public int getNumRecursos()
        {
            // Obtenemos la tabla recursos.
            DataTable t = new DataTable();
            t = vdb.Tables["Recursos"];

            // Devolvemos la cantidad de filas de la tabla.
            return t.Rows.Count;
        }

        /// <summary>
        /// Busca recursos por nombre y descripción.
        /// </summary>
        /// <param name="nombre">Filtro para el nombre.</param>
        /// <param name="descripcion">Filtro para la descripción.</param>
        /// <returns>Devuelve un ArrayList con los recursos que cumplen las restricciones de búsqueda.</returns>
        public ArrayList BuscarRecursos(string nombre, string descripcion)
        {
            // ArrayList de recursos.
            ArrayList lista = new ArrayList();
            
            // Obtenemos la tabla recursos.
            DataTable t = new DataTable();
            t = vdb.Tables["Recursos"];

            // Generamos la sentencia de selección.
            string select = "";
            int numcampos = 0;

            if (nombre != "")
            {
                select += @"nombre LIKE '%" + nombre + "%'";
                numcampos++;
            }
            if (descripcion != "")
            {
                if (numcampos > 0)
                {
                    select += " AND ";
                }
                select += @"descripcion LIKE '%" + descripcion + "%'";
                numcampos++;
            }

            // Obtenemos las filas que cumplen las restricciones de búsqueda.
            DataRow[] filas = t.Select(select);

            // Almacenamos cada una de las filas del resultado en el ArrayList.
            foreach (DataRow r in filas)
            {
                ENRecurso re = new ENRecurso();

                // Insertamos los datos en la nueva actividad.
                re.Nombre = r["nombre"].ToString().Trim();
                re.Ratio = Convert.ToInt32(r["cantidad_base"]);
                re.Descripcion = r["descripcion"].ToString().Trim();
                lista.Add(re);
            }

            // Devolvemos el resultado.
            return lista;
        }

        //////////////////////////////////////
        /// FUNCIONES USADAS EN CREARECURSO///
        //////////////////////////////////////

        /// <summary>
        /// Devuelve los ids de los recursos que puede crear los edificios
        /// </summary>
        /// <param name="edificio">Edificio del que queremos saber sus costes</param>
        /// <returns></returns>
        public ArrayList getRecursosEdificio(int edificio)
        {
            // ArrayList de recursos.
            ArrayList lista = new ArrayList();

            // Obtenemos la tabla CosteEdificio
            DataTable t = new DataTable();
            t = vdb.Tables["GeneraRecurso"];


            foreach (DataRow r in t.Select("nomEdificio = \'" + edificio + "\'"))
            {
                int un = Convert.ToInt32(r[1]);
                lista.Add(un);
            }

            return lista;
        }

        /// <summary>
        /// Añade un recurso a los que puede crear el edificio.
        /// </summary>
        /// <param name="edificio">Edificio creador</param>
        /// <param name="unidad">Recurso que puede ser creado</param>
        public void AñadeRecursoEdificio(int edificio, int recurso)
        {
            DataTable t = vdb.Tables["GeneraRecurso"];
            DataRow r = t.NewRow();

            r["nomedificio"] = edificio;
            r["nomrecurso"] = recurso;
            r["cantidad"] = 0;

            //MessageBox.Show(edificio + " " + unidad);
            try
            {
                t.Rows.Add(r);

                SqlCommandBuilder command = new SqlCommandBuilder(dae);

                // Actualizamos los cambios en la BD real.
                dae.Update(vdb, "GeneraRecurso");
            }
            catch
            {
                t.Rows.Remove(r);
            }
        }

        /// <summary>
        /// Insertamos en la tabla, que recursos puede crear un edificio.
        /// </summary>
        /// <param name="edificio">Edificio que creará los recursos.</param>
        /// <param name="unidades">Recursos que pueden ser creados.</param>
        public void AnadeRecursosEdificio(int edificio, ArrayList recursos)
        {
            DataTable t = vdb.Tables["GeneraRecurso"];   // Tabla antes de insertar lo nuevo.

            DataRow[] filas = t.Select("nomedificio = " + edificio);

            // Eliminamos las que ya no estén
            foreach (DataRow r in filas)
            {
                if (!recursos.Contains(r["nomrecurso"]))
                {
                    // Si no lo contiene habrá que eliminar en la tabla.
                    r.Delete();
                }
            }

            SqlCommandBuilder command = new SqlCommandBuilder(dae);

            // Actualizamos los cambios en la BD real.
            dae.Update(vdb, "GeneraRecurso");

            // Ahora insertamos las nuevas.
            foreach (int s in recursos)
            {
                AñadeRecursoEdificio(edificio, s);
            }
        }

        /// <summary>
        /// Elimina un recurso de los que puede crear el edificio.
        /// </summary>
        /// <param name="edificio">Edificio creador</param>
        /// <param name="unidad">Recurso que ya no puede ser creado</param>
        public void EliminaUnidadEdificio(string edificio, string recurso)
        {
            DataTable t = vdb.Tables["GeneraRecurso"];
            string select = "nomedificio = \'" + edificio + "\' and nomrecurso = \'" + recurso + "\'";

            try
            {
                DataRow r = t.Select(select)[0];
                r.Delete();

                SqlCommandBuilder command = new SqlCommandBuilder(dae);

                // Actualizamos los cambios en la BD real.
                dae.Update(vdb, "GeneraRecurso");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        /// <summary>
        /// Recoje de la base de los recursos que no pertenecen a la lista de excepción.
        /// </summary>
        /// <returns> Devuelve un ArrayList con los datos de los recursos no exentas.</returns>
        public ArrayList getRecursosExcepto(ArrayList listaExcepcion)
        {
            // ArrayList de unidades.
            ArrayList lista = new ArrayList();

            // Obtenemos la tabla unidad.
            DataTable t = new DataTable();
            t = vdb.Tables["Recursos"];

            // Realizamos un select de aquellas que no pertenecen a la lista de excepción.
            string select = "";
            bool primero = true;
            foreach (int nombre in listaExcepcion)
            {
                if (primero == true)
                {
                    select += "id <> " + nombre + " ";
                    primero = false;
                }
                else
                {
                    select += "and id <> " + nombre + " ";
                }
            }
            try
            {
                // Extraemos los ENUnidad de cada fila de la base de datos.
                foreach (DataRow r in t.Select(select))
                {
                    ENRecurso un = new ENRecurso();

                    // Insertamos los datos en la nueva actividad.
                    un.Id = Convert.ToInt32(r["id"]);
                    un.Nombre = r["nombre"].ToString().Trim();
                    un.Ratio = Convert.ToInt32(r["cantidad_base"]);
                    un.Descripcion = r["descripcion"].ToString().Trim();
                    un.Admin = r["admin"].ToString().Trim();
                    lista.Add(un);
                }
            }
            catch (Exception)
            {
                return null;
            }

            // Devolvemos el resultado.
            return lista;
        }

        public string getNombreRecurso(int id)
        {
            // Obtenemos la tabla unidad.
            DataTable t = vdb.Tables["Recursos"];
            string nomb = "";
            try
            {
                // Comprobamos si existe una unidad con ese id.
                DataRow r = t.Select("id = " + id)[0];

                // Extraemos el nombre de la unidad.
                nomb = r["nombre"].ToString();
            }
            catch (Exception)
            {
            }
            // Devolvemos el nombre.
            return nomb;
        }

        ////////////////////////////////////////
        /// FUNCIONES USADAS EN COSTEEDIFICIO///
        ////////////////////////////////////////

        /// <summary>
        /// Devuelve los ids de los recursos que cuesta un edificio
        /// </summary>
        /// <param name="edificio">Edificio del que queremos saber sus costes</param>
        /// <returns></returns>
        public ArrayList getCostesEdificio(int edificio)
        {
            // ArrayList de recursos.
            ArrayList lista = new ArrayList();

            // Obtenemos la tabla CosteEdificio
            DataTable t = new DataTable();
            t = vdb.Tables["CostesEdificio"];


            foreach (DataRow r in t.Select("nomEdificio = " + edificio + ""))
            {
                int un = Convert.ToInt32(r[1]);
                lista.Add(un);
            }

            return lista;
        }

        /// <summary>
        /// Añade un recurso a los que cuesta el edificio.
        /// </summary>
        /// <param name="edificio">Edificio</param>
        /// <param name="unidad">Nuevo coste</param>
        public void AñadeCosteEdificio(int edificio, int recurso)
        {
            DataTable t = vdb.Tables["CostesEdificio"];
            DataRow r = t.NewRow();

            r["nomedificio"] = edificio;
            r["nomrecurso"] = recurso;
            r["cantidad"] = 0;

            //MessageBox.Show(edificio + " " + unidad);
            try
            {
                t.Rows.Add(r);

                SqlCommandBuilder command = new SqlCommandBuilder(daec);

                // Actualizamos los cambios en la BD real.
                daec.Update(vdb, "CostesEdificio");
            }
            catch
            {
                t.Rows.Remove(r);
            }
        }

        /// <summary>
        /// Insertamos en la tabla, que recursos puede crear un edificio.
        /// </summary>
        /// <param name="edificio">Edificio que creará los recursos.</param>
        /// <param name="unidades">Recursos que pueden ser creados.</param>
        public void AnadeCostesEdificio(int edificio, ArrayList recursos)
        {
            DataTable t = vdb.Tables["CostesEdificio"];   // Tabla antes de insertar lo nuevo.

            DataRow[] filas = t.Select("nomedificio = " + edificio);

            // Eliminamos las que ya no estén
            foreach (DataRow r in filas)
            {
                if (!recursos.Contains(r["nomrecurso"]))
                {
                    // Si no lo contiene habrá que eliminar en la tabla.
                    r.Delete();
                }
            }

            SqlCommandBuilder command = new SqlCommandBuilder(daec);

            // Actualizamos los cambios en la BD real.
            daec.Update(vdb, "CostesEdificio");

            // Ahora insertamos las nuevas.
            foreach (int s in recursos)
            {
                AñadeCosteEdificio(edificio, s);
            }
        }

        /// <summary>
        /// Elimina un recurso de los que puede crear el edificio.
        /// </summary>
        /// <param name="edificio">Edificio creador</param>
        /// <param name="unidad">Recurso que ya no puede ser creado</param>
        public void EliminaCosteEdificio(string edificio, string recurso)
        {
            DataTable t = vdb.Tables["CostesEdificio"];
            string select = "nomedificio = \'" + edificio + "\' and nomrecurso = \'" + recurso + "\'";

            try
            {
                DataRow r = t.Select(select)[0];
                r.Delete();

                SqlCommandBuilder command = new SqlCommandBuilder(daec);

                // Actualizamos los cambios en la BD real.
                daec.Update(vdb, "CostesEdificio");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        ////////////////////////////////////////
        /// FUNCIONES USADAS EN COSTEUNIDADES///
        ////////////////////////////////////////

        /// <summary>
        /// Devuelve los ids de los recursos que cuesta una unidad
        /// </summary>
        /// <param name="edificio">Unidad de la que queremos saber sus costes</param>
        /// <returns></returns>
        public ArrayList getCostesUnidad(int unidad)
        {
            // ArrayList de recursos.
            ArrayList lista = new ArrayList();

            // Obtenemos la tabla CosteEdificio
            DataTable t = new DataTable();
            t = vdb.Tables["CostesUnidad"];


            foreach (DataRow r in t.Select("unidad = " + unidad + ""))
            {
                int un = Convert.ToInt32(r[1]);
                lista.Add(un);
            }

            return lista;
        }

        /// <summary>
        /// Añade un recurso a los que cuesta la unidad.
        /// </summary>
        /// <param name="edificio">Unidad</param>
        /// <param name="unidad">Nuevo coste</param>
        public void AñadeCosteUnidad(int unidad, int recurso)
        {
            DataTable t = vdb.Tables["CostesUnidad"];
            DataRow r = t.NewRow();

            r["unidad"] = unidad;
            r["recurso"] = recurso;
            r["cantidad"] = 0;

            try
            {
                t.Rows.Add(r);

                SqlCommandBuilder command = new SqlCommandBuilder(dauc);

                // Actualizamos los cambios en la BD real.
                dauc.Update(vdb, "CostesUnidad");
            }
            catch
            {
                t.Rows.Remove(r);
            }
        }

        /// <summary>
        /// Insertamos en la tabla, que recursos puede crear un edificio.
        /// </summary>
        /// <param name="unidad">Unidad que tendrá esos costes.</param>
        /// <param name="recursos">Recursos que se añadirán a los costes de la unidad.</param>
        public void AnadeCostesUnidad(int unidad, ArrayList recursos)
        {
            DataTable t = vdb.Tables["CostesUnidad"];   // Tabla antes de insertar lo nuevo.

            DataRow[] filas = t.Select("unidad = " + unidad);

            // Eliminamos las que ya no estén
            foreach (DataRow r in filas)
            {
                if (!recursos.Contains(r["recurso"]))
                {
                    // Si no lo contiene habrá que eliminar en la tabla.
                    r.Delete();
                }
            }

            SqlCommandBuilder command = new SqlCommandBuilder(dauc);

            // Actualizamos los cambios en la BD real.
            dauc.Update(vdb, "CostesUnidad");

            // Ahora insertamos las nuevas.
            foreach (int s in recursos)
            {
                AñadeCosteUnidad(unidad, s);
            }
        }

        /// <summary>
        /// Elimina un recurso de los que puede crear el edificio.
        /// </summary>
        /// <param name="unidad">Edificio creador</param>
        /// <param name="recurso">Recurso que ya no puede ser creado</param>
        public void EliminaCosteUnidad(string unidad, string recurso)
        {
            DataTable t = vdb.Tables["CostesUnidad"];
            string select = "unidad = \'" + unidad + "\' and recurso = \'" + recurso + "\'";

            try
            {
                DataRow r = t.Select(select)[0];
                r.Delete();

                SqlCommandBuilder command = new SqlCommandBuilder(dauc);

                // Actualizamos los cambios en la BD real.
                dauc.Update(vdb, "CostesUnidad");
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
    }
}
